#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <malloc.h>
#include <sys/time.h>
#include <stdarg.h>

#include <i264e_common.h>
#ifdef DMALLOC
#include <imp/dmalloc.h>
#endif
void i264e_param_default(i264e_param_t *param)
{
	if (NULL == param) {
		return;
	}
	memset(param, 0, sizeof(i264e_param_t));

	param->soc = C_T10;
	param->b_tlb = 0;
	param->b_use_phy = 1;
	param->b_user_fenc = 1;
	param->b_user_nalbuffer = 1;
	param->b_open_coop = 0;
	param->b_use_dn = 0;
	param->i_devid = -1;
	param->i_threads = 1;
	param->b_mref = 0;
	param->b_buf_share = 0;

	/* Video Properties */
	param->i_width = 1280;
	param->i_height = 720;
	param->i_csp = C_CSP_NV12;
	param->i_profile = -1;
	param->i_level_idc = -1;

	param->vui.i_sar_height = 0;
	param->vui.i_sar_width = 0;
	param->vui.i_overscan = C_OVERSCAN_UNDEF;
	param->vui.i_vidformat = C_VF_UNDEF;
	param->vui.b_fullrange = -1;
	param->vui.i_colorprim = 2;
	param->vui.i_transfer = 2;
	param->vui.i_colmatrix = -1;
	param->vui.i_chroma_loc = 0;

	param->i_dpb_size = 0;
	param->i_frame_reference = 1;

	param->b_deblocking_filter = 1;
	param->i_deblocking_filter_alphac0 = 0;
	param->i_deblocking_filter_beta = 0;

	param->b_cabac = 1;
	param->i_cabac_init_idc = 0;

    /* Encoder analyser parameters */
	param->analyse.i_weighted_pred = I264E_WEIGHTP_NONE;

    param->analyse.b_transform_8x8 = 1;
    //set same as: si->dct8x8_en ---/librc/enc_api_h264.c line 255

	param->analyse.i_chroma_qp_offset = 0;
	param->analyse.i_mv_range = -1; // set from level_idc
	param->analyse.i_subpel_refine = 7;
	param->analyse.b_fast_mvp = 1;
	param->analyse.b_psnr = 0;
	param->analyse.b_ssim = 0;

	/* skip control parameters */
	param->hskip.i_skip_type = C_STYPE_N1X;
	param->hskip.m = 0;
	param->hskip.n = 0;
	param->hskip.max_same_scenecnt = 0;
	param->hskip.b_enable_scenecut = 0;
	param->hskip.b_black_enhance = 0;
	param->i_max_skip_type = -1;

	/* Rate control parameters */
	param->rc.i_rc_method = I264E_RC_CBR;
	param->rc.i_qp_constant = 30;
	param->rc.i_qp_min = 0;
	param->rc.i_qp_max = QP_MAX;
	param->rc.f_rate_tolerance = 1.0;
	param->rc.f_ip_factor = 1.4;
	param->rc.f_pb_factor = 1.3;
	param->rc.i_bitrate = 2000;
    param->rc.i_fps_max = 1500;
    param->rc.i_fps_min = 1;
    param->rc.i_biaslvl = 0;
	param->rc.i_qp_step = 3;
    param->rc.i_gop_qp_step = 15;
    param->rc.b_adaptive_mode = false;
    param->rc.b_gop_relation = false;
	param->rc.i_static_time = 2;
	param->rc.i_max_bitrate = 0;
	param->rc.i_change_pos = 80;
    param->rc.i_quality_level = 4;
	param->rc.i_trigger_level = 3;
	param->rc.i_new_qp_max_thr = 51;
	param->rc.b_enable_mbrc = 1;
	param->rc.b_enable_change_ref = 1;

    param->superFrm.mode = SF_RE_ENOCDE;
    param->superFrm.iframe_bits_thresd = param->i_width * param->i_width * 3 / 2 * 8;
    param->superFrm.pframe_bits_thresd = param->superFrm.iframe_bits_thresd / param->rc.f_ip_factor;
    param->superFrm.bframe_bits_thresd = param->superFrm.pframe_bits_thresd / param->rc.f_pb_factor;
    param->superFrm.priority = SF_BITRATE_FIRST;

    param->denoise.i_dn_type = I264E_DN_NONE;
    param->denoise.i_itype_qp = 24;
    param->denoise.i_ptype_qp = 26;

	param->b_repeat_headers = 1;
	param->b_annexb = 1;

	param->i_sps_id = 0;
	param->b_vfr_input = 0;

	param->i_fps_num = 25;
	param->i_fps_den = 1;
	param->i_timebase_num = 0;
	param->i_timebase_den = 0;

	/* log */
	param->pf_log = c_log_default;
	param->module = "i264e";
	param->i_log_level = C_LOG_INFO;

	param->b_fisheye = 0;

	param->i_slice_count = 1;
	param->b_bs_save = 0;
	param->b_ref_save = 0;
	param->b_enc_save = 0;
	param->b_dec_save = 0;
}

static void i264e_set_aspect_ratio(i264e_t *h, i264e_param_t *param, int initial)
{
    /* VUI */
    if(param->vui.i_sar_width > 0 && param->vui.i_sar_height > 0) {
        uint32_t i_w = param->vui.i_sar_width;
        uint32_t i_h = param->vui.i_sar_height;
        uint32_t old_w = h->common.param.vui.i_sar_width;
        uint32_t old_h = h->common.param.vui.i_sar_height;

        c_reduce_fraction(&i_w, &i_h);

        while((i_w > 65535) || (i_h > 65535)) {
            i_w /= 2;
            i_h /= 2;
        }

        c_reduce_fraction(&i_w, &i_h);

        if(i_w != old_w || i_h != old_h || initial) {
            h->common.param.vui.i_sar_width = 0;
            h->common.param.vui.i_sar_height = 0;
            if(i_w == 0 || i_h == 0) {
                i264e_log(h, C_LOG_WARNING, "cannot create valid sample aspect ratio\n");
			} else {
                i264e_log(h, initial? C_LOG_INFO : C_LOG_DEBUG, "using SAR=%d/%d\n", i_w, i_h);
                h->common.param.vui.i_sar_width = i_w;
                h->common.param.vui.i_sar_height = i_h;
            }
        }
    }
}


int i264e_validate_parameters(i264e_t *h)
{
    int ratio = h->common.param.i_width > 800 ? 6 : 3;
	int max_superbs = ((h->common.param.i_width + 15) & ~15) * ((h->common.param.i_height + 15) & ~15) * 3 / 2 * 8 / ratio;
	int min_superbs = ((h->common.param.i_width + 15) & ~15) * ((h->common.param.i_height + 15) & ~15) * 3 / 2 * 8 / 200;

	if (h->common.param.i_threads > I264E_THREAD_MAX) {
		i264e_log(h, C_LOG_WARNING, "reduce threads to the max thread num is:%d\n",
				I264E_THREAD_MAX);
		h->common.param.i_threads = I264E_THREAD_MAX;
	}

	if ((h->common.param.i_width > 2336) || (h->common.param.i_height < 16) ||
			(h->common.param.i_width % 16) || (h->common.param.i_height % 2)) {
		i264e_log(h, C_LOG_ERROR, "invalid width x height (%dx%d)\n",
				h->common.param.i_width, h->common.param.i_height);
		goto err_resolution;
	}

	if (h->common.param.i_devid >= 0) {
		h->common.param.b_open_coop = 0;
	}

	//h->common.param.i_profile = c_clip3(h->common.param.i_profile, -1, PROFILE_HIGH);
	h->common.param.i_profile = PROFILE_HIGH;   //only support PROFILE_HIGH

	if ((h->common.param.i_csp != C_CSP_NV12) && (h->common.param.i_csp != C_CSP_T420)) {
		i264e_log(h, C_LOG_ERROR, "invalid final encode color space:%d (only support NV12"
			" or T420)\n", h->common.param.i_csp);
		goto err_csp;
	}

    if((h->common.param.vui.i_sar_width <= 0) || (h->common.param.vui.i_sar_height <= 0)) {
		h->common.param.vui.i_sar_width = 0;
		h->common.param.vui.i_sar_height = 0;
    }

	if ((h->common.param.vui.i_overscan < C_OVERSCAN_UNDEF)
			|| (h->common.param.vui.i_overscan > C_OVERSCAN_HAVE)) {
		i264e_log(h, C_LOG_ERROR, "invalid overscan:%d\n", h->common.param.vui.i_overscan);
		goto err_overscan;
	}

    if(((h->common.param.crop.i_left+h->common.param.crop.i_right)>=h->common.param.i_width)
		||((h->common.param.crop.i_top+h->common.param.crop.i_bottom)>=h->common.param.i_height)) {
        i264e_log(h, C_LOG_ERROR, "invalid crop:%u,%u,%u,%u\n",
				h->common.param.crop.i_left, h->common.param.crop.i_top,
				h->common.param.crop.i_right, h->common.param.crop.i_bottom);
		goto err_crop;
    }

    h->common.param.rc.i_fps_max = c_clip3(h->common.param.rc.i_fps_max, 1, I264E_KEYINT_MAX_INFINITE );
	h->common.param.i_threads = c_clip3(h->common.param.i_threads, 1, I264E_THREAD_MAX);


    if(h->common.param.rc.i_fps_max == 1)
    {
        h->common.param.analyse.i_weighted_pred = 0;
        h->common.param.i_frame_reference = 1;
        h->common.param.i_dpb_size = 1;
    }

    if((h->common.param.rc.i_rc_method < I264E_RC_CQP)||(h->common.param.rc.i_rc_method >= I264E_RC_INV)) {
        i264e_log( h, C_LOG_ERROR, "no ratecontrol method specified\n" );
		goto err_rc_method;
    }

    h->common.param.rc.i_qp_constant = c_clip3(h->common.param.rc.i_qp_constant, 0, QP_MAX);
    h->common.param.rc.f_ip_factor = C_MAX( h->common.param.rc.f_ip_factor, 0.01f );
    h->common.param.rc.f_pb_factor = C_MAX( h->common.param.rc.f_pb_factor, 0.01f );

    if(h->common.param.rc.i_rc_method == I264E_RC_CQP) {
        float qp_p = h->common.param.rc.i_qp_constant;
        float qp_i = qp_p - 6*log2f(h->common.param.rc.f_ip_factor);
        float qp_b = qp_p + 6*log2f(h->common.param.rc.f_pb_factor);
        h->common.param.rc.i_qp_min = c_clip3((int)(C_MIN3(qp_p, qp_i, qp_b)), 0, QP_MAX);
        h->common.param.rc.i_qp_max = c_clip3((int)(C_MAX3(qp_p, qp_i, qp_b) + .999),
				0, QP_MAX);
    }
    h->common.param.rc.i_qp_max = c_clip3(h->common.param.rc.i_qp_max, 0, QP_MAX);
    h->common.param.rc.i_qp_min = c_clip3(h->common.param.rc.i_qp_min, 0,
			h->common.param.rc.i_qp_max);

    h->common.param.rc.i_biaslvl = c_clip3(h->common.param.rc.i_biaslvl, -10, 10);
    h->common.param.rc.i_qp_step = c_clip3(h->common.param.rc.i_qp_step, 2, QP_MAX);
    h->common.param.rc.i_gop_qp_step = c_clip3(h->common.param.rc.i_gop_qp_step, 2, QP_MAX);

	h->common.param.rc.i_static_time = C_MAX(h->common.param.rc.i_static_time, 1);
	h->common.param.rc.i_max_bitrate = C_MAX(h->common.param.rc.i_max_bitrate, 128);
	h->common.param.rc.i_change_pos = c_clip3(h->common.param.rc.i_change_pos, 50, 100);
	h->common.param.rc.i_quality_level = c_clip3(h->common.param.rc.i_quality_level, 0, 6);
	h->common.param.rc.i_trigger_level = c_clip3(h->common.param.rc.i_trigger_level, 2, 10);
	h->common.param.rc.i_new_qp_max_thr = c_clip3(h->common.param.rc.i_new_qp_max_thr, h->common.param.rc.i_qp_max, QP_MAX);

	/* for the macro ratecontrol not adjust to denoise code, so close it excpet t10 */
	if (h->common.param.soc == C_T10) {
		h->common.param.denoise.i_dn_type = c_clip3(h->common.param.denoise.i_dn_type, I264E_DN_NONE, I264E_DN_II);
		h->common.param.denoise.i_itype_qp = c_clip3(h->common.param.denoise.i_itype_qp, 0, QP_MAX);
		h->common.param.denoise.i_ptype_qp = c_clip3(h->common.param.denoise.i_ptype_qp, 0, QP_MAX);
		if (!h->common.param.b_use_dn) {
			h->common.param.denoise.i_dn_type = I264E_DN_NONE;
		}
	} else {
		h->common.param.b_use_dn = 0;
		memset(&h->common.param.denoise, 0, sizeof(i264e_denoise_t));
	}

    h->common.param.superFrm.mode = c_clip3(h->common.param.superFrm.mode, SF_DO_NOTHING, SF_RE_ENOCDE);
    h->common.param.superFrm.iframe_bits_thresd = c_clip3(h->common.param.superFrm.iframe_bits_thresd, min_superbs, max_superbs);
    h->common.param.superFrm.pframe_bits_thresd = c_clip3(h->common.param.superFrm.pframe_bits_thresd, min_superbs, h->common.param.superFrm.iframe_bits_thresd / h->common.param.rc.f_ip_factor);
    h->common.param.superFrm.bframe_bits_thresd = c_clip3(h->common.param.superFrm.bframe_bits_thresd, min_superbs, h->common.param.superFrm.pframe_bits_thresd / h->common.param.rc.f_pb_factor);
    h->common.param.superFrm.priority = c_clip3(h->common.param.superFrm.priority, SF_PR_NOTHING, SF_FRAMEBITS_FIRST);

    if(!h->common.param.i_fps_num || !h->common.param.i_fps_den/* || !h->common.param.b_vfr_input*/) {
        h->common.param.i_fps_num = 25;
        h->common.param.i_fps_den = 1;
    }

    h->common.param.rc.i_fps_min = c_clip3(h->common.param.rc.i_fps_min, 1, h->common.param.rc.i_fps_max);

    if(!h->common.param.i_timebase_num || !h->common.param.i_timebase_den) {
        h->common.param.i_timebase_num = h->common.param.i_fps_den;
        h->common.param.i_timebase_den = h->common.param.i_fps_num;
    }

    c_reduce_fraction(&h->common.param.i_fps_num, &h->common.param.i_fps_den);
    c_reduce_fraction(&h->common.param.i_timebase_num, &h->common.param.i_timebase_den);

    if((uint64_t)h->common.param.i_timebase_den * 2 > UINT32_MAX) {
        i264e_log(h, C_LOG_ERROR, "Effective timebase denominator %u exceeds H.264 maximum\n",
				h->common.param.i_timebase_den);
        goto err_i_timebase_den;
    }
    i264e_set_aspect_ratio(h, &h->common.param, 1);

	if (h->common.param.i_gop <= 0) {
		h->common.param.i_gop = c_clip3(h->common.param.i_fps_num, h->common.param.rc.i_fps_min,
				h->common.param.rc.i_fps_max);
	}

    h->common.param.i_deblocking_filter_alphac0 = c_clip3(
			h->common.param.i_deblocking_filter_alphac0, -6, 6);
    h->common.param.i_deblocking_filter_beta = c_clip3(
			h->common.param.i_deblocking_filter_beta, -6, 6);

	h->common.param.b_cabac = 1;
    h->common.param.i_cabac_init_idc = c_clip3(h->common.param.i_cabac_init_idc, 0, 2);
	h->common.param.hskip.i_skip_type = c_clip3(h->common.param.hskip.i_skip_type, C_STYPE_N1X,
			C_STYPE_H1M_TRUE);
	if (h->common.param.b_buf_share || h->common.param.b_mref) {
		h->common.param.hskip.i_skip_type = C_STYPE_N1X;
		h->common.param.i_max_skip_type = C_STYPE_N1X;
		h->common.param.b_use_dn = 0;			//if use buf share, should't open 2pass encode
	}
    if (h->common.param.rc.i_rc_method == I264E_RC_SMART) {
		if (h->common.param.b_buf_share) {	//for only support N1X and H1M_FALSE skip type
			h->common.param.hskip.m = h->common.param.i_gop - 1;
			h->common.param.hskip.n = 1;
		} else {
			switch(h->common.param.hskip.i_skip_type) {
				case C_STYPE_N1X:
				case C_STYPE_H1M_FALSE:
				case C_STYPE_H1M_TRUE:
					h->common.param.hskip.m = h->common.param.i_gop - 1;
					h->common.param.hskip.n = 1;
					break;
				case C_STYPE_N2X:
					h->common.param.hskip.m = 1;
					h->common.param.hskip.n = 1;
					break;
				case C_STYPE_N4X:
					h->common.param.hskip.m = 1;
					h->common.param.hskip.n = 2;
					break;
				case C_STYPE_HN1_FALSE:
				case C_STYPE_HN1_TRUE:
					h->common.param.hskip.m = 1;
					h->common.param.hskip.n = h->common.param.i_gop - 1;
					break;
				default:
					h->common.param.hskip.i_skip_type = C_STYPE_N1X;
					h->common.param.hskip.m = h->common.param.i_gop - 1;
					h->common.param.hskip.n = 1;
					break;
			}
		}
    } else {
        memset(&h->common.param.hskip, 0, sizeof(c_high_skip_t));
    }

	h->common.param.hskip.m = c_clip3(h->common.param.hskip.m, 0, 1000);
	h->common.param.hskip.n = c_clip3(h->common.param.hskip.n, 0, 1000);
	h->common.param.hskip.max_same_scenecnt = c_clip3(h->common.param.hskip.max_same_scenecnt, 1, 100);
	h->common.param.rc.i_static_time = c_clip3(h->common.param.rc.i_static_time, 1, h->common.param.hskip.max_same_scenecnt);
	if (h->common.param.i_max_skip_type < 0) {
		h->common.param.i_max_skip_type = c_clip3(h->common.param.i_max_skip_type, h->common.param.hskip.i_skip_type, C_STYPE_H1M_TRUE);
	}

	if (h->common.param.b_mref) {
		h->common.param.i_frame_reference = 2;
	} else {
		h->common.param.i_frame_reference = (h->common.param.i_max_skip_type < C_STYPE_N2X) ? 1 : 2;
	}
	h->common.param.i_frame_reference = c_clip3(h->common.param.i_frame_reference,
			1, I264E_REF_MAX);
	h->common.param.i_dpb_size = h->common.param.i_frame_reference;


    h->common.param.analyse.i_subpel_refine = c_clip3(h->common.param.analyse.i_subpel_refine,
			0, 11);
    if( h->common.param.i_log_level < C_LOG_INFO) {
        h->common.param.analyse.b_psnr = 0;
        h->common.param.analyse.b_ssim = 0;
    }
    h->common.param.analyse.i_chroma_qp_offset = c_clip3(
			h->common.param.analyse.i_chroma_qp_offset, -12, 12);

    h->common.param.analyse.i_weighted_pred = c_clip3(h->common.param.analyse.i_weighted_pred,
			I264E_WEIGHTP_NONE, I264E_WEIGHTP_SMART);

	if(h->common.param.rc.f_rate_tolerance < 0)
		h->common.param.rc.f_rate_tolerance = 0;

    h->common.param.i_sps_id &= 31;

	h->common.param.i_slice_count = c_clip3(h->common.param.i_slice_count, 0, 1);


	{
		const i264e_level_t *l = i264e_levels;
		if(h->common.param.i_level_idc < 0) {
			i264e_sps_init(h->common.sps, h->common.param.i_sps_id, &h->common.param);
			do {
				h->common.param.i_level_idc = l->level_idc;
			} while(l[1].level_idc && i264e_validate_levels(h, 0) && l++);
		} else {
			while(l->level_idc && l->level_idc != h->common.param.i_level_idc) {
				l++;
			}
			if( l->level_idc == 0 ) {
				i264e_log(h, C_LOG_ERROR, "invalid level_idc: %d\n", h->common.param.i_level_idc );
				goto err_level_idc;
			}
		}
        if( h->common.param.analyse.i_mv_range <= 0 )
            h->common.param.analyse.i_mv_range = l->mv_range;
        else
            h->common.param.analyse.i_mv_range = c_clip3(h->common.param.analyse.i_mv_range, 32, 512);
	}

	if (!h->common.param.b_user_fenc && ((h->common.param.ckmalloc == NULL)
				|| (h->common.param.ckfree == NULL) || (h->common.param.ckvirt_to_phys == NULL)
				|| (h->common.param.ckphys_to_virt == NULL))) {
		h->common.param.ckmalloc = c_malloc;
		h->common.param.ckfree = c_free;
		h->common.param.ckvirt_to_phys = c_virt_to_phys;
		h->common.param.ckphys_to_virt = c_phys_to_virt;
	}  else if ((h->common.param.ckmalloc == NULL) || (h->common.param.ckfree == NULL)){
		i264e_log(h, C_LOG_ERROR, "invalidate malloc func\n");
		goto err_invalidate_malloc_func;
	}

#define BOOLIFY(x) h->common.param.x = !!h->common.param.x
    BOOLIFY( b_tlb );
    BOOLIFY( b_user_fenc );
    BOOLIFY( b_open_coop );
    BOOLIFY( b_use_dn );
	BOOLIFY( b_mref );
	BOOLIFY( b_buf_share );
    BOOLIFY( b_cabac );
    BOOLIFY( b_deblocking_filter );
    BOOLIFY( b_repeat_headers );
    BOOLIFY( b_annexb );
    BOOLIFY( b_vfr_input );
    BOOLIFY( analyse.b_transform_8x8 );
    BOOLIFY( analyse.b_fast_mvp );
    BOOLIFY( analyse.b_psnr );
    BOOLIFY( analyse.b_ssim );
    BOOLIFY( hskip.b_enable_scenecut );
    BOOLIFY( hskip.b_black_enhance );
    BOOLIFY( rc.b_adaptive_mode );
    BOOLIFY( rc.b_gop_relation );
    BOOLIFY( rc.b_enable_mbrc );
    BOOLIFY( rc.b_enable_change_ref );
#undef BOOLIFY

	return 0;

err_invalidate_malloc_func:
err_level_idc:
err_i_timebase_den:
err_rc_method:
err_crop:
err_overscan:
err_csp:
err_resolution:
	return -1;
}

#define I264E_SPRINTF_INT(a,b) s += sprintf(s, "%s=%d\n", a, b)
#define I264E_SPRINTF_UINT(a,b) s += sprintf(s, "%s=%u\n", a, b)
#define I264E_SPRINTF_STR(a,b) s += sprintf(s, "%s=%s\n", a, b)
#define I264E_SPRINTF_FLOAT(a,b) s += sprintf(s, "%s=%f\n", a, b)
#define I264E_SPRINTF_P(a,b) s += sprintf(s, "%s=%p\n", a, b)
#define IS_IN_RANGE(a, x, y) (((a) >= (x))&&((a) <= (y)))
char *i264e_param2string(i264e_param_t *p, int b_res)
{
    int len = 4096;
    char *buf, *s;
	int i = 0;
    buf = s = malloc(len);
    if(!buf)
        return buf;

    if(b_res)
    {
        s += sprintf( s, "%dx%d \n", p->i_width, p->i_height );
        s += sprintf( s, "fps=%u/%u \n", p->i_fps_num, p->i_fps_den );
        s += sprintf( s, "timebase=%u/%u \n", p->i_timebase_num, p->i_timebase_den );
        s += sprintf( s, "bitdepth=%d \n", 8/*BIT_DEPTH*/ );
    }
	I264E_SPRINTF_INT("soc", p->soc);
	I264E_SPRINTF_INT("b_tlb", p->b_tlb);
	I264E_SPRINTF_INT("b_user_fenc", p->b_user_fenc);
	I264E_SPRINTF_INT("i_devid", p->i_devid);
	I264E_SPRINTF_INT("b_open_coop", p->b_open_coop);
	I264E_SPRINTF_INT("i_threads", p->i_threads);


	/* Video Properties */

	I264E_SPRINTF_INT("i_csp", p->i_csp);
	I264E_SPRINTF_INT("i_level_idc", p->i_level_idc);
	/* VUI */
	I264E_SPRINTF_INT("vui.i_sar_height",	p->vui.i_sar_height);
	I264E_SPRINTF_INT("vui.i_sar_width",		p->vui.i_sar_width);
	I264E_SPRINTF_STR("vui.i_overscan",		IS_IN_RANGE(p->vui.i_overscan, 0, ARRAY_ELEMS(i264e_overscan_names)-1)?i264e_overscan_names[p->vui.i_overscan]:"error");
	I264E_SPRINTF_STR("vui.i_vidformat",		IS_IN_RANGE(p->vui.i_vidformat, 0, ARRAY_ELEMS(i264e_vidformat_names)-1)?i264e_vidformat_names[p->vui.i_vidformat]:"error");
	I264E_SPRINTF_STR("vui.b_fullrange",		IS_IN_RANGE(p->vui.b_fullrange, 0, ARRAY_ELEMS(i264e_fullrange_names)-1)?i264e_fullrange_names[p->vui.b_fullrange]:"error");
	I264E_SPRINTF_STR("vui.i_colorprim",		IS_IN_RANGE(p->vui.i_colorprim, 0, ARRAY_ELEMS(i264e_colorprim_names)-1)?i264e_colorprim_names[p->vui.i_colorprim]:"error");
	I264E_SPRINTF_STR("vui.i_transfer",		IS_IN_RANGE(p->vui.i_transfer, 0, ARRAY_ELEMS(i264e_transfer_names)-1)?i264e_transfer_names[p->vui.i_transfer]:"error");
	I264E_SPRINTF_STR("vui.i_colmatrix",		IS_IN_RANGE(p->vui.i_colmatrix, 0, ARRAY_ELEMS(i264e_colmatrix_names)-1)?i264e_colmatrix_names[p->vui.i_colmatrix]:"error");
	I264E_SPRINTF_INT("vui.i_chroma_loc",	p->vui.i_chroma_loc);

    /* Bitstream parameters */
	I264E_SPRINTF_INT("i_dpb_size", p->i_dpb_size);
	I264E_SPRINTF_INT("i_frame_reference", p->i_frame_reference);
	I264E_SPRINTF_INT("b_deblocking_filter", p->b_deblocking_filter);
	I264E_SPRINTF_INT("i_deblocking_filter_alphac0", p->i_deblocking_filter_alphac0);
	I264E_SPRINTF_INT("i_deblocking_filter_beta", p->i_deblocking_filter_beta);
	I264E_SPRINTF_INT("b_cabac", p->b_cabac);
	I264E_SPRINTF_INT("i_cabac_init_idc", p->i_cabac_init_idc);
    /* Encoder analyser parameters */
	I264E_SPRINTF_INT("analyse.i_weighted_pred", p->analyse.i_weighted_pred);
	I264E_SPRINTF_INT("analyse.b_transform_8x8", p->analyse.b_transform_8x8);
	I264E_SPRINTF_INT("analyse.i_chroma_qp_offset", p->analyse.i_chroma_qp_offset);
	I264E_SPRINTF_INT("analyse.i_mv_range", p->analyse.i_mv_range);
	I264E_SPRINTF_INT("analyse.i_subpel_refine", p->analyse.i_subpel_refine);
	I264E_SPRINTF_INT("analyse.b_fast_mvp", p->analyse.b_fast_mvp);
	I264E_SPRINTF_INT("analyse.b_psnr", p->analyse.b_psnr);
	I264E_SPRINTF_INT("analyse.b_ssim", p->analyse.b_ssim);
	/* skip control parameters */
	I264E_SPRINTF_INT("hskip.i_skip_type", p->hskip.i_skip_type);
	I264E_SPRINTF_INT("hskip.m", p->hskip.m);
	I264E_SPRINTF_INT("hskip.n", p->hskip.n);
	/* Rate control parameters */
	I264E_SPRINTF_INT("rc.i_rc_method", p->rc.i_rc_method);
	I264E_SPRINTF_INT("rc.i_qp_constant", p->rc.i_qp_constant);
	I264E_SPRINTF_INT("rc.i_qp_min", p->rc.i_qp_min);
	I264E_SPRINTF_INT("rc.i_qp_max", p->rc.i_qp_max);
	I264E_SPRINTF_INT("rc.i_qp_step", p->rc.i_qp_step);
	I264E_SPRINTF_INT("rc.i_qp_step", p->rc.i_qp_step);
	I264E_SPRINTF_FLOAT("rc.f_rate_tolerance", p->rc.f_rate_tolerance);
	I264E_SPRINTF_FLOAT("rc.f_ip_factor", p->rc.f_ip_factor);
	I264E_SPRINTF_FLOAT("rc.f_pb_factor", p->rc.f_pb_factor);
	/* roi */
	for (i = 0; i < 8; i++) {
		s += sprintf(s, "roi[%d].roi_en=%u\n", i, p->roi[i].roi_en);
		s += sprintf(s, "roi[%d].roi_md=%u\n", i, p->roi[i].roi_md);
		s += sprintf(s, "roi[%d].roi_qp=%u\n", i, p->roi[i].roi_qp);
		s += sprintf(s, "roi[%d].roi_lmbx=%u\n", i, p->roi[i].roi_lmbx);
		s += sprintf(s, "roi[%d].roi_rmbx=%u\n", i, p->roi[i].roi_rmbx);
		s += sprintf(s, "roi[%d].roi_umby=%u\n", i, p->roi[i].roi_umby);
		s += sprintf(s, "roi[%d].roi_bmby=%u\n", i, p->roi[i].roi_bmby);
	}
	/* Cropping Rectangle parameter */
	I264E_SPRINTF_UINT("crop.i_left", p->crop.i_left);
	I264E_SPRINTF_UINT("crop.i_top", p->crop.i_top);
	I264E_SPRINTF_UINT("crop.i_right", p->crop.i_right);
	I264E_SPRINTF_UINT("crop.i_bottom", p->crop.i_bottom);
    /* Muxing parameters */
	I264E_SPRINTF_INT("b_repeat_headers", p->b_repeat_headers);
	I264E_SPRINTF_INT("b_annexb", p->b_annexb);
	I264E_SPRINTF_INT("i_sps_id", p->i_sps_id);
	I264E_SPRINTF_INT("b_vfr_input", p->b_vfr_input);
	I264E_SPRINTF_INT("b_vfr_input", p->b_vfr_input);
	/* Log */
	I264E_SPRINTF_P("pf_log", p->pf_log);
	I264E_SPRINTF_STR("p_log_private", p->module);
	I264E_SPRINTF_INT("i_log_level", p->i_log_level);
	I264E_SPRINTF_INT("i_slice_count", p->i_slice_count);
	/* buf managememt */
	I264E_SPRINTF_P("malloc", p->ckmalloc);
	I264E_SPRINTF_P("free", p->ckfree);
    return buf;
}

void i264e_log(i264e_t *h, int i_level, const char *psz_fmt, ... )
{
    if(!h || i_level <= h->common.param.i_log_level) {
        va_list arg;
        va_start( arg, psz_fmt );
        if(!h)
            c_log_default("i264e", i_level, psz_fmt, arg);
        else
            h->common.param.pf_log(h->common.param.module, i_level, psz_fmt, arg);
        va_end(arg);
    }
}
